
#include "stdafx.h"
#include "VideoPlayer.h"

namespace SmallMediaLibrary{

	VideoPlayer::VideoPlayer()
	{
		mMemoryRenderer = 0;
	}

	VideoPlayer::~VideoPlayer()
	{
		
	}

	void VideoPlayer::AddVideoRenderer()
	{
		/* 
		 * See the AppFilter example from GDCL for creating and consuming filters without wrapping in COM objects.
		 * (They do custom DirectShow implementations - check them out if you have a budget! - info@gdcl.co.uk)
		 * http://www.gdcl.co.uk/ 
		 */

		if(mMemoryRenderer)
		{
			mMemoryRenderer->Release();
			mMemoryRenderer = 0;
		}

		HRESULT result = S_OK;
		VideoMemoryRenderer* localMemoryRenderer = new VideoMemoryRenderer(NULL, &result);
		localMemoryRenderer->AddRef();

		if(!SUCCEEDED(result))
		{
			String^ message = String::Format("Unable to create Video to Memory Render filter object {0}", result);
			throw gcnew System::Exception(message);
		}
		mMemoryRenderer = localMemoryRenderer;

		mMemoryRenderer->Player = this;
		mMemoryRenderer->ReceivingFrame = defaultFrame;

		IBaseFilter* pInterfaceInfo;
		mMemoryRenderer->QueryInterface(IID_IBaseFilter, (void**)(&pInterfaceInfo));

		if(!SUCCEEDED(result))
		{
			String^ message = String::Format("Unable to get the interface for the Video to Memory filter {0}", result);
			throw gcnew System::Exception(message);
		}

		mGraphBuilder->AddFilter(pInterfaceInfo, MemoryRendererName);
		pInterfaceInfo->Release();		
	}

	// Loads the provided file and creates a filter graph automatically
	void VideoPlayer::Load(String^ filename)
	{
		//http://www.flipcode.com/archives/DirectShow_For_Media_Playback_In_Windows-Part_III_Customizing_Graphs.shtml

		Initialise();
		AddVideoRenderer();

		pin_ptr<const wchar_t> wFilename = PtrToStringChars(filename);
		mGraphBuilder->RenderFile(wFilename, NULL);

		int pin_count = mMemoryRenderer->GetPinCount();
		if(pin_count > 1)
		{
			String^ message = String::Format("MemoryRenderer reports more than one pins. Since this is a renderer, there should be only one pin. Pin Count: {0}", pin_count);
			throw gcnew System::Exception(message);
		}

		CBasePin* input_pin = mMemoryRenderer->GetPin(0);
		if(!input_pin->IsConnected())
		{		
			String^ message = String::Format("DirectShow was not able to connect MemoryRenderer to the graph. Likely no common format could be agreed with the decoder.");
			throw gcnew System::Exception(message);
		}

		REFERENCE_TIME duration;
		mMediaSeeking->GetDuration(&duration);
		mDuration = duration;
	}	

	void VideoPlayer::SetReceivingFrame(VideoFrame^ frame)
	{
		defaultFrame = frame;
		if(mMemoryRenderer)
		{
			EnterCriticalSection(&(mMemoryRenderer->receivingFrameMutex));
			mMemoryRenderer->ReceivingFrame = frame;
			LeaveCriticalSection(&(mMemoryRenderer->receivingFrameMutex));
		}
	}

	void VideoPlayer::OverrideSourceRegion(Region^ rect)
	{
		mMemoryRenderer->SourceRegion = rect->ToRect();
	}
}